home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Disc to the Future 2
/
Disc to the Future Part II Programmer's Reference (Wayzata Technology)(6013)(1992).bin
/
MAC
/
MPW_TOOL
/
TOOLS
/
TOOLS_WI
/
ICON_8
/
ICONX_FO
/
FMEMMON.C
< prev
next >
Wrap
Text File
|
1990-03-02
|
14KB
|
593 lines
/*
* fxmemmon.c -- mmout, mmpause, mmshow, and internal functions.
*
* This file contains memory monitoring code. It is compiled by inclusion
* in fxtra.c if MemMon is defined. When MemMon is undefined, most of the
* "MMxxxx" entry points are defined as null macros in rt.h.
*/
#include "::h:config.h"
#include "::h:rt.h"
#include "rproto.h"
#ifdef PreProcess
/* include(../M4/fncs.m4) /* */
/* */
#endif /* PreProcess */
#ifdef MemMon
/*
* Prototypes.
*/
hidden novalue mmcmd Params((word addr, word len, int c));
hidden novalue mmdec Params((uword n));
hidden novalue mmforget Params((noargs));
hidden novalue mmlen Params((word n, int c));
hidden novalue mmnewline Params((noargs));
hidden novalue mmrefresh Params((noargs));
hidden novalue mmsizes Params((int c));
hidden novalue mmstatic Params((noargs));
hidden novalue MMOut Params((char *prefix, char *msg));
static FILE *monfile = NULL; /* output file pointer */
static char *monname = NULL; /* output file name */
static word llen = 0; /* current output line length */
static char typech[MaxType+1]; /* output character for each type */
/* Define size of curlength table, and bias needed to access it. */
/* Assumes all type codes are printable characters (or space). */
/* Smaller table is used if not EBCDIC. */
#if !EBCDIC
#define CurSize (127 - ' ')
#define CurBias ' '
#else /* !EBCDIC */
#define CurSize 256
#define CurBias 0
#endif /* !EBCDIC */
static word curlength[CurSize]; /* current length for each output character */
/* line limit: start a new line when a command goes beyond this column */
#define LLIM 70
/* mmchar(c): output character c and update the column counter */
#define mmchar(c) (llen++,putc((c),monfile))
/* mmspace(): output unneeded whitespace whitespace following a command */
/* define as "mmchar(' ')" for readable files, or as "0" for compact ones */
#define mmspace() 0
/*
* mmout(s) - write the given string to the MemMon file.
*/
FncDcl(mmout,1)
{
char sbuf[MaxCvtLen];
int t;
if ((t = defstr(&Arg1, sbuf, &emptystr)) == Error)
RunErr(0, NULL);
/*
* Make sure Arg1 is a C-style string.
*/
if (t == NoCvt)
qtos(&Arg1, sbuf);
MMOut("", StrLoc(Arg1));
Arg0 = nulldesc;
Return;
}
/*
* mmpause(s) - pause MemMon displaying string s.
*/
FncDcl(mmpause,1)
{
char sbuf[MaxCvtLen];
int t;
if ((t = defstr(&Arg1, sbuf, &emptystr)) == Error)
RunErr(0, NULL);
if (StrLen(Arg1) == 0)
MMOut("; ", "programmed pause");
else {
/*
* Make sure Arg1 is a C-style string.
*/
if (t == NoCvt)
qtos(&Arg1, sbuf);
MMOut("; ", StrLoc(Arg1));
}
Arg0 = nulldesc;
Return;
}
/*
* mmshow(x, s) - alter MemMon display of x depending on s.
*/
FncDcl(mmshow,2)
{
char sbuf[MaxCvtLen];
/*
* Default Arg2 to the empty string and make sure it is a C-style string.
*/
switch (defstr(&Arg2, sbuf, &emptystr)) {
case Cvt: /* Already converted to a C-style string */
break;
case Defaulted:
case NoCvt:
qtos(&Arg2, sbuf);
break;
case Error:
RunErr(0, NULL);
}
MMShow(&Arg1, StrLoc(Arg2));
Arg0 = nulldesc;
Return;
}
/*
* MMInit(filename) - initialization.
*
* Memory monitoring is activated if the environment variable MEMMON is
* non-null. Its value names the output file; or, under Unix, a value
* beginning with "|" specifies a command to which the output is piped.
*
* If MemMon is defined on a system lacking environment variables,
* monitoring is always activated and output is to the file "memmon.out".
*/
novalue MMInit(filename)
char *filename;
{
int i;
FILE *f;
char time_buf[26];
#ifdef EnvVars
monname = getenv("MEMMON");
if (monname == NULL || strlen(monname) == 0)
return;
#else /* EnvVars */
monname = "memmon.out";
#endif /* EnvVars */
#if UNIX
if (monname[0] == '|')
f = popen(monname+1, "w");
else
#endif /* UNIX */
f = fopen(monname, "w");
if (f == NULL) {
fprintf(stderr, "MEMMON: cannot open %s\n", monname);
fflush(stderr);
exit(ErrorExit);
}
getctime(time_buf);
fprintf(f, "## Icon MemMon output\n");
fprintf(f, "#\n");
fprintf(f, "# program: %s\n", filename);
fprintf(f, "# date: %s\n", time_buf);
for (i = 0; i <= MaxType; i++)
typech[i] = '?'; /* initialize with error character */
#ifdef LargeInts
typech[T_Bignum] = 'i'; /* long integer */
#endif /* LargeInts */
typech[T_Real] = 'r'; /* real number */
typech[T_Cset] = 'c'; /* cset */
typech[T_File] = 'f'; /* file block */
typech[T_Record] = 'R'; /* record block */
typech[T_Tvsubs] = 'u'; /* substring trapped variable */
typech[T_External]= 'E'; /* external block */
typech[T_List] = 'L'; /* list header block */
typech[T_Lelem] = 'l'; /* list element block */
typech[T_Table] = 'T'; /* table header block */
typech[T_Telem] = 't'; /* table element block */
typech[T_Tvtbl] = 'e'; /* table elem trapped variable*/
typech[T_Set] = 'S'; /* set header block */
typech[T_Selem] = 's'; /* set element block */
typech[T_Slots] = 'h'; /* set/table hash slots */
typech[T_Coexpr] = 'X'; /* co-expression block (static region) */
typech[T_Refresh] = 'x'; /* co-expression refresh block */
/*
* codes used elsewhere but not shown here:
* in the static region: 'A' = alien (malloc block), 'F' = free
* in the string region: '"' = string
*/
/*
* Set monfile to indicate that memmon is active. Don't set it earlier
* than this, or we'll loop trying to trace the garbage collection that
* creates the buffer space.
*/
monfile = f;
mmrefresh(); /* show current state */
fflush(monfile); /* force it out */
}
/*
* MMTerm(part1, part2) - terminate memory monitoring.
* part1 and part2 are concatentated to form an explanatory message.
*/
novalue MMTerm(part1, part2)
char *part1, *part2;
{
FILE *f;
if (monfile == NULL)
return;
mmnewline();
mmsizes('='); /* make a final check on region sizes */
if (*part1 || *part2) /* if any reason given, write it as comment */
fprintf(monfile, "# %s%s\n", part1, part2);
f = monfile;
monfile = NULL; /* so we don't try to show the freeing of the buffer */
#if UNIX
if (monname[0] == '|')
pclose(f);
else
#endif /* UNIX */
fclose(f);
}
/*
* MMStat(a, n, c) - note static block at a, length n, represented by char 'c'.
* Output values are in basic units (typically words).
*/
novalue MMStat(a, n, c)
char *a;
word n;
int c;
{
#ifndef FixedRegions
if (monfile == NULL)
return;
mmcmd(DiffPtrs(a, statbase) / MMUnits, n / MMUnits, c);
#endif /* FixedRegions */
}
/*
* MMAlc(len, type) - note an allocation at the end of the block region.
*/
novalue MMAlc(len, type)
word len;
int type;
{
if (monfile == NULL)
return;
mmcmd((word)(-1), len / MMUnits, typech[type]);
}
/*
* MMStr(len) - note a string allocation at the end of the string region.
*/
novalue MMStr(slen)
word slen;
{
if (monfile == NULL)
return;
mmcmd((word)(-1), slen, '"');
}
/*
* MMBGC() - begin garbage collection.
*/
novalue MMBGC(region)
int region;
{
if (monfile == NULL)
return;
mmsizes('='); /* write current sizes */
fprintf(monfile, "%d{\n", region); /* indicate start of g.c. */
fflush(monfile);
mmforget(); /* clear memory of block sizes */
}
/*
* MMEGC() - end garbage collection.
*/
novalue MMEGC()
{
if (monfile == NULL)
return;
mmnewline();
fprintf(monfile, "}\n"); /* indicate end of marking */
mmrefresh(); /* redraw regions after compaction */
fprintf(monfile, "!\n"); /* indicate end of g.c. */
fflush(monfile);
}
/*
* MMMark(block, type) - mark indicated block during garbage collection.
*/
novalue MMMark(block, type)
char *block;
int type;
{
if (monfile == NULL)
return;
mmcmd(DiffPtrs(block, blkbase) / MMUnits, (word)BlkSize(block) / MMUnits,
typech[type]);
}
/*
* MMSMark - Mark String.
*/
novalue MMSMark(saddr, slen)
char *saddr;
word slen;
{
if (monfile == NULL)
return;
mmcmd(DiffPtrs(saddr, strbase), slen, '"');
}
/*
* MMOut(prefix, msg) - write the prefix and message to the MemMon output file.
*/
static novalue MMOut(prefix, msg)
char *prefix, *msg;
{
if (monfile == NULL)
return;
mmnewline();
fprintf(monfile, "%s%s\n", prefix, msg);
}
/*
* MMShow(d, s) - redraw block indicated by descriptor d according to flags
* in s.
*/
novalue MMShow(d, s)
dptr d;
char *s;
{
char *block;
uword addr;
word len;
char cmd, tch;
if (monfile == NULL)
return;
if (Qual(*d)) {
/*
* Show a string.
*/
/*
if ((uword)StrLoc(*d)<(uword)strbase || (uword)StrLoc(*d)>=(uword)strend)
*/
if (!InRange(strbase,StrLoc(*d),strend))
return; /* ignore if outside string region */
addr = DiffPtrs(StrLoc(*d), strbase);
len = StrLen(*d);
cmd = '$';
tch = '"';
}
else if (Type(*d)==T_Coexpr) {
/*
* Show a coexpression block, which will be in the static region.
*/
block = (char *)BlkLoc(*d);
addr = DiffPtrs(block, statbase) / MMUnits;
len = BlkSize(block) / MMUnits;
cmd = 'Y';
tch = typech[T_Coexpr];
}
else if (Pointer(*d)) {
/*
* Show something in the block region.
*/
block = (char *)BlkLoc(*d);
/*
if ((uword)block < (uword)blkbase || (uword)block >= (uword)blkfree)
*/
if (!InRange(blkbase,block,blkfree))
return; /* ignore if outside block region */
addr = DiffPtrs(block, blkbase) / MMUnits;
len = BlkSize(block) / MMUnits;
cmd = '%';
tch = typech[Type(*d)];
}
mmdec(addr); /* address */
mmchar('+');
mmlen(len, cmd); /* length, and $ Y or % command */
if (s && *s)
mmchar(*s); /* color flag from mmshow call */
else
mmchar('r'); /* default color is 'r' (redraw) */
mmchar(tch); /* block type character */
if (llen >= LLIM)
mmnewline();
else
mmspace();
}
/*
* mmrefresh() - redraw screen, initially or after garbage collection.
*/
static novalue mmrefresh()
{
char *p;
word n;
mmnewline();
mmsizes('<'); /* signal start of screen refresh */
mmnewline();
mmforget(); /* clear memory of past sizes */
mmstatic(); /* show the static region */
mmnewline();
for (p = blkbase; p < blkfree; p += n)
MMAlc(n = BlkSize(p), (int)BlkType(p));/* block region */
mmnewline();
MMStr(DiffPtrs(strfree, strbase)); /* string region */
mmnewline();
fprintf(monfile, ">\n"); /* signal end of refresh */
mmsizes('='); /* confirm region sizes */
mmforget(); /* clear memory of past sizes */
}
/*
* mmstatic() - recap the static region (stack, coexprs, aliens, free)
* (this function is empty under FixedRegions)
*/
static novalue mmstatic()
{
#ifndef FixedRegions
HEADER *p;
char *a;
int h;
word n;
for (p = (HEADER *)statbase; (uword)p < (uword)(HEADER *)statfree;
p += p->s.bsize) {
a = (char *)(p + 1);
n = (p->s.bsize - 1) * sizeof(HEADER);
h = *(int *)a;
if (h == T_Coexpr || a == (char *)stack)
MMStat(a, n, 'X'); /* coexpression block */
else if (h == FREEMAGIC)
MMStat(a, n, 'F'); /* free block */
else
MMStat(a, n, 'A'); /* alien block */
}
a = (char *)p;
if (a < statend)
MMStat(a, (word)(statend-a), 'F');/* rest of static region is free */
#endif /* FixedRegions */
}
/*
* mmsizes(c) - output current region sizes, with initial character c.
* If c is '<', the unit size is written ahead of it.
*/
static novalue mmsizes(c)
int c;
{
mmnewline();
if (c == '<')
fprintf(monfile, "%d", MMUnits);
fprintf(monfile, "%c %lu:%lu/%lu %lu:%lu/%lu %lu:%lu/%lu\n", c,
/* static region; show as full, actual amount is unknown */
(unsigned long)statbase,
(unsigned long)DiffPtrs(statend, statbase),
(unsigned long)DiffPtrs(statend, statbase),
/* string region */
(unsigned long)strbase,
(unsigned long)DiffPtrs(strfree, strbase),
(unsigned long)DiffPtrs(strend, strbase),
/* block region */
(unsigned long)blkbase,
(unsigned long)DiffPtrs(blkfree, blkbase),
(unsigned long)DiffPtrs(blkend, blkbase));
}
/*
* mmcmd(addr, len, c) - output a memmon command.
* If addr is < 0, it is omitted.
* If len matches the previous value for command c, it is also omitted.
* If the output fills the line, a following newline is written.
*/
static novalue mmcmd(addr, len, c)
word addr, len;
int c;
{
if (addr >= 0) {
mmdec((uword)addr);
mmchar('+');
}
mmlen(len, c);
if (llen >= LLIM)
mmnewline();
else
mmspace();
}
/*
* mmlen(n, c) - output length n with character c.
* Omit the length if it matches the previous value for c.
*/
static novalue mmlen(n, c)
word n;
int c;
{
if (n != curlength[c-CurBias])
mmdec((uword)(curlength[c-CurBias] = n));
mmchar(c);
}
/*
* mmdec(n) - output a decimal value, updating the line length.
*/
static novalue mmdec (n)
uword n;
{
if (n > 9)
mmdec(n / 10);
n %= 10;
mmchar('0'+(int)n);
}
/*
* mmnewline() - output a newline and reset the line length.
*/
static novalue mmnewline()
{
if (llen > 0) {
putc('\n', monfile);
llen = 0;
}
}
/*
* mmforget() - clear the history of remembered lengths.
*/
static novalue mmforget()
{
int c;
for (c = 0; c < CurSize; c++)
curlength[c] = -1;
}
#else /* MemMon */
static char x; /* avoid empty module */
#endif /* MemMon */